package com.amir.common.utils

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Log
import com.amir.common.utils.image.ImageScale
import id.zelory.compressor.constraint.QualityConstraint
import id.zelory.compressor.constraint.ResolutionConstraint
import id.zelory.compressor.constraint.SizeConstraint
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream


object ImageUtils {

    fun getCompressBitmapFile(file: File, width: Int, height: Int): File? {
        val cachPath = "${Utils.getContext().cacheDir.path}${File.separator}compressor${File.separator}"
        var resultFile = file.copyTo(File("${cachPath}${file.name}"), true)
        val resolution = ResolutionConstraint(width, height)
        val quality = QualityConstraint(80)
        val size = SizeConstraint(2_097_152)
        if(resolution.isSatisfied(resultFile).not()){
            resolution.satisfy(resultFile)
        }
        if(quality.isSatisfied(resultFile).not()){
            quality.satisfy(resultFile)
        }
        if(size.isSatisfied(resultFile).not()){
            size.satisfy(resultFile)
        }
        return resultFile
    }

    fun getCompressBitmap(bitmap: Bitmap, scale: ImageScale?): Bitmap? {
        if (scale != null) {
            var h: Int = scale.height
            val outWidth = bitmap.width
            val outHeight = bitmap.height
            if(outWidth <= scale.width || outHeight <= scale.height){
                return bitmap
            }
            if (scale.isKeepProportion) {
                val percent: Float = scale.width * 1f / outWidth
                val nHeight = outHeight * percent
                h = nHeight.toInt()
            }
            /**
             * 1.计算需要压缩的比例
             * 2.按将图片用计算出的比例压缩,并加载至内存中使用
             */
            // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4
            val inSampleSize: Int = calculateInSampleSize(outWidth, outHeight, scale.width, h)
            Log.v("hhhhhhh", String.format("outWidth: %d , outHeight: %d , inSampleSize: %d",outWidth, outHeight, inSampleSize));
            // 利用计算的比例值获取压缩后的图片对象
            return compressBySampleSize(bitmap, inSampleSize)
        }
        return bitmap
    }

    fun getCompressBitmap(path: String?, scale: ImageScale?): Bitmap? {
        if (scale != null) {
            /**
             * 1.获取图片的像素宽高(不加载图片至内存中,所以不会占用资源)
             * 2.计算需要压缩的比例
             * 3.按将图片用计算出的比例压缩,并加载至内存中使用
             */
            // 首先不加载图片,仅获取图片尺寸
            val options = BitmapFactory.Options()

            // 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息
            options.inJustDecodeBounds = true
            // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象
            BitmapFactory.decodeFile(path, options)
            var h: Int = scale.height
            if (scale.isKeepProportion) {
                val ow = options.outWidth
                val oh = options.outHeight
                val percent: Float = scale.width * 1f / ow
                val nh = oh * percent
                h = nh.toInt()
            }
            // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4
            options.inSampleSize =
                calculateInSampleSize(options.outWidth, options.outHeight, scale.width, h)

            // 当inJustDecodeBounds设为false时,BitmapFactory.decode...就会返回图片对象了
            options.inJustDecodeBounds = false
            options.inScaled = false
            // 利用计算的比例值获取压缩后的图片对象
            return BitmapFactory.decodeFile(path, options)
        }
        return getBitmap(path)
    }

    /**
     * 获取bitmap
     *
     * @param filePath 文件路径
     * @return bitmap
     */
    fun getBitmap(filePath: String?): Bitmap? {
        return if (isSpace(filePath)) null else BitmapFactory.decodeFile(filePath)
    }

    /**
     * 获取bitmap
     *
     * @param file 文件
     * @return bitmap
     */
    fun getBitmap(file: File?): Bitmap? {
        if (file == null) return null
        var inputStream: InputStream? = null
        return try {
            inputStream = BufferedInputStream(FileInputStream(file))
            BitmapFactory.decodeStream(inputStream)
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
            null
        } finally {
            CloseUtils.closeIO(inputStream)
        }
    }

    /**
     * 保存图片
     *
     * @param src      源图片
     * @param filePath 要保存到的文件路径
     * @param format   格式
     * @return `true`: 成功<br></br>`false`: 失败
     */
    fun save(src: Bitmap, filePath: String?, format: Bitmap.CompressFormat?): Boolean {
        return save(src, FileUtils.getFileByPath(filePath), format, false)
    }

    /**
     * 保存图片
     *
     * @param src    源图片
     * @param file   要保存到的文件
     * @param format 格式
     * @return `true`: 成功<br></br>`false`: 失败
     */
    fun save(src: Bitmap, file: File?, format: Bitmap.CompressFormat?): Boolean {
        return save(src, file, format, false)
    }

    /**
     * 保存图片
     *
     * @param src      源图片
     * @param filePath 要保存到的文件路径
     * @param format   格式
     * @param recycle  是否回收
     * @return `true`: 成功<br></br>`false`: 失败
     */
    fun save(
        src: Bitmap,
        filePath: String?,
        format: Bitmap.CompressFormat?,
        recycle: Boolean
    ): Boolean {
        return save(src, FileUtils.getFileByPath(filePath), format, recycle)
    }

    /**
     * 保存图片
     *
     * @param src     源图片
     * @param file    要保存到的文件
     * @param format  格式
     * @param recycle 是否回收
     * @return `true`: 成功<br></br>`false`: 失败
     */
    fun save(src: Bitmap, file: File?, format: Bitmap.CompressFormat?, recycle: Boolean): Boolean {
        if (isEmptyBitmap(src) || !FileUtils.createOrExistsFile(file)) return false
        println(src.width.toString() + ", " + src.height)
        var os: OutputStream? = null
        var ret = false
        try {
            os = BufferedOutputStream(FileOutputStream(file))
            ret = src.compress(format, 100, os)
            if (recycle && !src.isRecycled) src.recycle()
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            CloseUtils.closeIO(os)
        }
        return ret
    }

    /**
     * 计算压缩比例值
     *
     * @param outHeight 原始图片高度
     * @param outWidth  原始图片宽度
     * @param reqWidth  所需图片压缩尺寸最小宽度
     * @param reqHeight 所需图片压缩尺寸最小高度
     * @return
     */
    private fun calculateInSampleSize(outWidth: Int, outHeight: Int, reqWidth: Int, reqHeight: Int): Int {

        // 初始化压缩比例为1
        var inSampleSize = 1

        // 当图片宽高值任何一个大于所需压缩图片宽高值时,进入循环计算系统
        if (outHeight > reqHeight || outWidth > reqWidth) {
            val halfHeight = outHeight / 2
            val halfWidth = outWidth / 2

            // 压缩比例值每次循环两倍增加,
            // 直到原图宽高值的一半除以压缩值后都~大于所需宽高值为止
            while (halfHeight / inSampleSize >= reqHeight
                && halfWidth / inSampleSize >= reqWidth
            ) {
                inSampleSize *= 2
            }
        }
        return inSampleSize
    }

    /**
     * 按采样大小压缩
     *
     * @param src        源图片
     * @param sampleSize 采样率大小
     * @return 按采样率压缩后的图片
     */
    private fun compressBySampleSize(src: Bitmap, sampleSize: Int): Bitmap? {
        return compressBySampleSize(src, sampleSize, false)
    }

    /**
     * 按采样大小压缩
     *
     * @param src        源图片
     * @param sampleSize 采样率大小
     * @param recycle    是否回收
     * @return 按采样率压缩后的图片
     */
    private fun compressBySampleSize(src: Bitmap, sampleSize: Int, recycle: Boolean): Bitmap? {
        if (isEmptyBitmap(src)) return null
        val options = BitmapFactory.Options()
        options.inSampleSize = sampleSize
        val baos = ByteArrayOutputStream()
        src.compress(Bitmap.CompressFormat.JPEG, 100, baos)
        val bytes = baos.toByteArray()
        if (recycle && !src.isRecycled) src.recycle()
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)
    }

    /**
     * 判断bitmap对象是否为空
     *
     * @param src 源图片
     * @return `true`: 是<br></br>`false`: 否
     */
    private fun isEmptyBitmap(src: Bitmap?): Boolean {
        return src == null || src.width == 0 || src.height == 0
    }

    private fun isSpace(s: String?): Boolean {
        if (s == null) return true
        var i = 0
        val len = s.length
        while (i < len) {
            if (!Character.isWhitespace(s[i])) {
                return false
            }
            ++i
        }
        return true
    }
}